#include "Query.h"
#include <algorithm>
/**
 * @brief 
 * 
 * @param os 
 * @param query 
 * @return std::ostream& 
 */
std::ostream & operator<< (std::ostream &os, const Query &query)
{
    return os << query.rep(); // Query;:rep 通过它额 Query_base 指针对 rep() 进行了虚调用
}
/**
 * @brief 返回运算对象查询结果 set 的并集
 * 
 * @param text 
 * @return QueryResult 
 */
QueryResult 
OrQuery::eval(const TextQuery& text) const
{
    // 通过 Query 成员 lhs 和 rhs 进行的虚调用
    // 调用 eval 返回每个运算对象的 QueryResult
    auto right = rhs.eval(text), left = lhs.eval(text);
    // 将左侧运算对象的行号拷贝到结果 set 中
    auto ret_lines = std::make_shared<std::set<line_no>>(left.begin(), left.end());
    // 插入右侧运算对象所得的行号
    ret_lines->insert(right.begin(), right.end());
    // 返回一个新的 QueryResult， 它表示 lhs 和 rhs 的并集
    return QueryResult(rep(), ret_lines, left.get_file());
}
/**
 * @brief 返回运算对象查询结果 set 的交集
 * 
 * @param text 
 * @return QueryResult 
 */
QueryResult
AndQuery::eval(const TextQuery &text) const
{
    // 通过 Query 运算对象进行的虚调用，以获得运算对象的查询结果 set
    auto left = lhs.eval(text);
    auto right = rhs.eval(text);
    // 保存 left 和 right 交集的 set
    auto ret_lines = std::make_shared<std::set<line_no>>();
    // 将两个范围的交集写入一个目的迭代器中
    // 本次调用的目的迭代器向 ret 添加元素
    std::set_intersection(left.begin(), left.end(),
                          right.begin(), right.end(),
                          std::inserter(*ret_lines, ret_lines->begin()));
    return QueryResult(rep(), ret_lines, left.get_file());
}
/**
 * @brief 返回运算对象的结果 set 中不存在的行
 * 
 * @param text 
 * @return QueryResult 
 */
QueryResult
NotQuery::eval(const TextQuery &text) const
{
    // 通过 Query 运算对象对 eval 进行虚调用
    auto result = query.eval(text);
    // 开始时结果 set 为空
    auto ret_lines = std::make_shared<std::set<line_no>>();
    // 我们必须在运算对象出现的所有行中进行迭代
    auto beg = result.begin();
    auto end = result.end();
    // 对于输入文件的每一行，如果改行不在 result 当中，则将其添加到 ret_lines
    auto sz = result.get_file()->size();
    for(size_t n = 0; n != sz; ++n)
    {
        // 如果我们还没有处理完 result 的所有行，检查当前行是否存在
        if(beg == end || *beg != n)
        {
            ret_lines->insert(n); // 如果不在 result 当中，添加这一行
        }
        else if(beg != end)
        {
            ++beg; // 否则继续获取 result 的下一行(如果有的话)
        }
    }
    return QueryResult(rep(), ret_lines, result.get_file());
}
